package com.bruce.exec.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.text.StrPool;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.nio.charset.StandardCharsets;
import java.rmi.ServerRuntimeException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern;

/**
 * @author xin.ding
 * @date 2021/4/16 21:06
 */
public class ProcessUtils {

    /** Windows classpath分隔符 */
    public static final String WINDOWS_CLASSPATH_SEPARATOR = ";";

    /** Linux classpath分隔符 */
    public static final String LINUX_CLASSPATH_SEPARATOR = ":";

    private ProcessUtils() {
        throw new UnsupportedOperationException();
    }

    /**
     * 获取Classpath分割符号
     *
     * @return
     */
    public static String getClasspathSeparator() {
        if (Platform.isWindows()) {
            return WINDOWS_CLASSPATH_SEPARATOR;
        } else {
            return LINUX_CLASSPATH_SEPARATOR;
        }
    }


    /**
     * 获取进程执行的输出信息
     *
     * @param process
     */
    public static void getProcessOutput(Process process) {
        try (BufferedReader infoInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
             BufferedReader errorInput = new BufferedReader(new InputStreamReader(process.getErrorStream()));) {
            String line;
            while ((line = infoInput.readLine()) != null) {
                Console.log(line);
            }
            while ((line = errorInput.readLine()) != null) {
                Console.error(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

//    /**
//     * 构建Java进程执行命令
//     *
//     * @param jarFile   jar 文件
//     * @param mainClass 运行main-class名称,如果可以从Jar中获取则取Jar中的main-calss
//     * @param extra     额外加载的目录或文件(绝对路径)
//     * @return
//     */
//    public static List<String> buildRunCmd(File jarFile, String mainClass, String... extra) {
//        try {
//            List<String> commands = new ArrayList<>(16);
//            commands.add("java");
//            commands.add("-cp");
//            String runClasspath = buildRunClasspath(jarFile, extra);
//            commands.add(runClasspath);
//            String mainClassName = getMainClassName(jarFile, mainClass);
//            commands.add(mainClassName);
//            return commands;
//        } catch (Exception e) {
//            throw new ServerRuntimeException("进程执行命令生成失败,{}", e.getMessage());
//        }
//    }


    /**
     * 构建Jar包运行ClassPath
     * <p>
     * windows: xxx.jar;lib/*;.
     * linux:   xxx.jar:lib/*:.
     *
     * @param jarFile jar文件
     * @param extra   文件或目录(绝对路径)
     * @return
     */
    public static String buildRunClasspath(File jarFile, String... extra) {
        try {
            StrBuilder classpathBuilder = new StrBuilder();

            if (jarFile != null) {
                classpathBuilder.append(jarFile.getAbsolutePath()).append(getClasspathSeparator());
            }

            // 处理要加载的目录或文件
            for (String s : extra) {
                File file = FileUtil.file(s);
                if (file.exists()) {
                    if (file.isDirectory()) {
                        classpathBuilder.append(s).append(File.separator).append("*").append(getClasspathSeparator());
                    } else if (file.isFile()) {
                        classpathBuilder.append(s).append(getClasspathSeparator());
                    }
                }
            }
            classpathBuilder.append(StrPool.DOT);
            return classpathBuilder.toString();
        } catch (Exception e) {
            throw new RuntimeException("进程执行命令生成失败");
        }
    }


    /**
     * 获取当前进程PID
     *
     * @return
     */
    public static int getCurrentPid() {
        return Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
    }

    /**
     * 获取进程id
     *
     * @param pName 程序名
     * @return pid
     */
    public static String getPid(String pName) {
        return Platform.getProcessHandler().getProcessId(pName);
    }

    /**
     * 获取进程id
     *
     * @param pName   程序名
     * @param process 进程对象
     * @return pid
     */
    public static String getPid(String pName, Process process) {
        if (Platform.isWindows()) {
            return Platform.getProcessHandler().getProcessId(pName);
        }
        return Platform.getProcessHandler().getProcessId(process);
    }

    /**
     * 获取进程ID
     *
     * @return pid
     */
    public static String getPid() {
        String name = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
        return name.split("@")[0];
    }

    /**
     * 获取进程id
     *
     * @param process 进程对象
     * @return pid
     */
    public static String getPid(Process process) {
        return Platform.getProcessHandler().getProcessId(process);
    }

    /**
     * 程序是否正在运行
     *
     * @param pName 程序名
     * @return bool
     */
    public static boolean isActivePName(String pName) {
        return Platform.getProcessHandler().isActivePName(pName);
    }

    /**
     * 程序是否正在运行
     *
     * @param pid 进程id
     * @return bool
     */
    public static boolean isActivePid(String pid) {
        return Platform.getProcessHandler().isActivePid(pid);
    }

    /**
     * kill 进程,kill之前验证是否在运行
     *
     * @param pid 进程id
     */
    public static boolean validAndKillProcess(String pid) {
        if (!isActivePid(pid)) {
            return true;
        }
        return Platform.getProcessHandler().killProcess(pid);
    }

    /**
     * kill 进程
     *
     * @param pid 进程id
     */
    public static boolean killProcess(String pid) {
        return Platform.getProcessHandler().killProcess(pid);
    }

    /**
     * 获取java进程 名称匹配的 pid集合
     *
     * @param regex 正则表达式
     * @return list
     */
    public static List<Integer> getJarPids(String regex) {
        List<Integer> ids = new ArrayList<>();
        Pattern p = Pattern.compile(regex);

        Runtime runtime = Runtime.getRuntime();
        try {
            Process pro = runtime.exec("jps -l");
            BufferedReader br = new BufferedReader(new InputStreamReader(pro.getInputStream(), StandardCharsets.UTF_8));
            String str = "";
            while ((str = br.readLine()) != null) {
                if (str.trim().equals("") || !p.matcher(str).matches()) {
                    continue;
                }
                ids.add(Integer.parseInt(str.substring(0, str.indexOf(" "))));
            }
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ids;
    }

    /**
     * <p>
     * 执行CMD命令
     * </p>
     *
     * @param commandLine 命令
     */
    public static String execute(String commandLine) {
        try {
            String[] cmd = new String[3];
            Properties props = System.getProperties();
            String osName = props.getProperty("os.name").toLowerCase();
            String charset = null;
            StringBuilder result = new StringBuilder();

            if (osName.startsWith("windows")) {
                cmd[0] = "cmd.exe";
                cmd[1] = "/C";
                cmd[2] = commandLine;
                charset = "GBK";
            } else if (osName.startsWith("linux")) {
                cmd[0] = "sh";
                charset = "UTF-8";
            }

            Process ps = Runtime.getRuntime().exec(cmd);
            String line;
            BufferedReader input = new BufferedReader(new InputStreamReader(ps.getInputStream(), charset));
            while ((line = input.readLine()) != null) {
                result.append(line).append(StrPool.LF);
            }
            input.close();
            ps.destroy();
            return result.toString();
        } catch (Exception e) {

        }
        return "";
    }

    /**
     * 是否windows系统
     */
    public static boolean isWindows() {
        String osName = System.getProperties().getProperty("os.name");
        return osName.toLowerCase().startsWith("windows");
    }

}
